﻿module Octopus.OctopusService.Database.HyperVNodes

open System.Data
open System.Data.SqlClient
open System.Data.SqlTypes
open System.Threading
open Octopus.OctopusLib
open Octopus.OctopusService.Database.Core


let insertHyperVNode (host:HyperVNode) =
    use cmd = new SqlCommand(CommandTimeout=10)

    cmd.CommandText <- "INSERT INTO [OctopusDb].[dbo].[HyperVNodes]" +
                       " ([HostName],[IpAddress],[ExternalNIC],[CpuCount],[MemorySize],[IsReachable],[LastCounterUpdated])" +
                       " VALUES (@HostName,@IpAddress,@ExternalNIC,@CpuCount,@MemorySize,@IsReachable,@LastCounterUpdated)"

    let dbNull = System.DBNull.Value

    cmd.Parameters.AddWithValue("@HostName", host.HostName) |> ignore
    if host.IpAddress = null then
      cmd.Parameters.AddWithValue("@IpAddress", dbNull) |> ignore
    else
      cmd.Parameters.AddWithValue("@IpAddress", host.IpAddress.ToString()) |> ignore
    cmd.Parameters.AddWithValue("@ExternalNIC", host.ExternalNIC_Guid) |> ignore
    cmd.Parameters.AddWithValue("@CpuCount", int host.CpuCount) |> ignore
    cmd.Parameters.AddWithValue("@MemorySize", int64 host.MemorySize) |> ignore
    cmd.Parameters.AddWithValue("@IsReachable", host.IsReachable) |> ignore
    cmd.Parameters.AddWithValue("@LastCounterUpdated", System.DateTime.Now) |> ignore
    
    use conn = connectoToOctopusDb()
    try
      cmd.Connection <- conn
      cmd.ExecuteNonQuery() |> ignore
    finally
      conn.Close()


let updateHyperVNode_reachable (hostname:string) (cpuCount:int, memorySize:int64, ipAddress:System.Net.IPAddress, lastcpuload:float32, lastmemoryfree:int64) =
    use cmd = new SqlCommand(CommandTimeout=10)

    cmd.CommandText <- "UPDATE [OctopusDb].[dbo].[HyperVNodes] SET " +
                        "[IsReachable]='TRUE', [CpuCount]=@cpuCount, [MemorySize]=@memorySize, [IpAddress]=@ipAddress, " + 
                        "[LastCpuLoad]=@lastCpuLoad, [LastMemoryFree]=@lastMemoryFree, [LastCounterUpdated]=@lastCounterUpdate " +
                        "WHERE [HostName]=@hostName"
                     
    cmd.Parameters.AddWithValue("@hostName", hostname) |> ignore
    cmd.Parameters.AddWithValue("@cpuCount", cpuCount) |> ignore
    cmd.Parameters.AddWithValue("@memorySize", memorySize) |> ignore
    cmd.Parameters.AddWithValue("@ipAddress", ipAddress.ToString()) |> ignore
    cmd.Parameters.AddWithValue("@lastCpuLoad", lastcpuload) |> ignore
    cmd.Parameters.AddWithValue("@lastMemoryFree", lastmemoryfree) |> ignore
    let timeStr = System.DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss")
    cmd.Parameters.AddWithValue("@lastCounterUpdate", timeStr) |> ignore

    use conn = connectoToOctopusDb()
    try
      cmd.Connection <- conn
      cmd.ExecuteNonQuery() |> ignore
    finally
      conn.Close()

let updateHyperVNode_unreachable (hostname:string) =
    use cmd = new SqlCommand(CommandTimeout=10)

    cmd.CommandText <- "UPDATE [OctopusDb].[dbo].[HyperVNodes] SET [IsReachable]='FALSE' WHERE [HostName]=@hostName"                     
    cmd.Parameters.AddWithValue("@hostName", hostname) |> ignore

    use conn = connectoToOctopusDb()
    try
      cmd.Connection <- conn
      cmd.ExecuteNonQuery() |> ignore
    finally
      conn.Close()


  //------------------------------------

module private HyperVNodesQuery =
    let getSelect() =
        "SELECT [ID],[HostName],[IpAddress],[ExternalNIC],[CpuCount],[MemorySize],[IsReachable],[LastCpuLoad],[LastMemoryFree],[LastCounterUpdated] FROM [OctopusDb].[dbo].[HyperVNodes]"
    let getSelectWhere cond =
        getSelect() + " WHERE " + cond

let private getHyperVNodesWithQuery (cmd:SqlCommand) =
    use reader = cmd.ExecuteReader()
    try
      [| while reader.Read() do
           let id = reader.GetInt32(0)
           let hostname = reader.GetString(1)
           let ipaddress = if reader.IsDBNull(2) then null else reader.GetString(2)
           let externalNic = reader.GetGuid(3)
           let cpucount = reader.GetInt32(4)
           let memorysize = reader.GetInt64(5)
           let isreachable = reader.GetBoolean(6)
           let lastcpuload = if reader.IsDBNull(7) then 0.0f else reader.GetFloat(7)
           let lastmemoryfree = if reader.IsDBNull(8) then 0L else reader.GetInt64(8)
           let lastcounterupdated = reader.GetDateTime(9)
           let node = new HyperVNode(id, hostname, ipaddress, externalNic, uint16 cpucount, uint64 memorysize, isreachable, lastcpuload, uint64 lastmemoryfree, lastcounterupdated)
           yield node |]
    finally
      reader.Close()

let getHyperVNodes () =
    let query = HyperVNodesQuery.getSelect()
    use conn = connectoToOctopusDb()
    use cmd = new SqlCommand(query, conn)

    try getHyperVNodesWithQuery cmd
    finally conn.Close()

let getHyperVNodeByName (hostname:string) =
    let hostname = hostname.Trim().ToUpper()
    let cond = sprintf "[HostName]='%s'" hostname
    let query = HyperVNodesQuery.getSelectWhere(cond)
    use conn = connectoToOctopusDb()
    use cmd = new SqlCommand(query, conn)

    try
      let x = (getHyperVNodesWithQuery cmd)
      if x.Length = 0 then failwith "Server not found" 
      x.[0]
    finally
      conn.Close()

let getHyperVNodesReachableWithMemoryFree (minMemoryFree:uint64) =
    let cond = sprintf "[LastMemoryFree] >= '%d'" minMemoryFree
    let query = HyperVNodesQuery.getSelectWhere(cond)
    use conn = connectoToOctopusDb()
    use cmd = new SqlCommand(query, conn)

    try getHyperVNodesWithQuery cmd
    finally conn.Close()

let getHyperVNodesUnreachable () =
    let cond = "[IsReachable]='false'"
    let query = HyperVNodesQuery.getSelectWhere(cond)
    use conn = connectoToOctopusDb()
    use cmd = new SqlCommand(query, conn)

    try getHyperVNodesWithQuery cmd
    finally conn.Close()

